package streamforce.crypto.cloud.subscriber;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import streamforce.Stat;
import streamforce.crypto.KPAbe;
import streamforce.crypto.cloud.EPCloud;
import streamforce.crypto.cloud.EPCloudServer;
import streamforce.crypto.cloud.TimeTuple;
import streamforce.crypto.cloud.Tuple;
import streamforce.crypto.event.Ciphertext;
import streamforce.crypto.event.TransformedCTEventAllAgg3;
import streamforce.crypto.policies.Policy;

//Aggregate 3 implementation at the cloud
public class CloudSumPriceAgg3 extends CloudSumPriceAgg2{
	final Log log = LogFactory.getLog(CloudSumPriceAgg3.class);
	byte[] ro, rt; 
	byte[][] po, pt; 
	byte[] prodO, prodT; 
	int windowSize;
	int rId; 
	Stat statTuple; 
	public CloudSumPriceAgg3(int pi, int rpi, int windowSize, KPAbe ch){
		super(pi, ch);
		this.rId = rpi; 
		this.windowSize = windowSize;
		this.statTuple = new Stat("nTuples"); 
	}		
	
	//the ciphertext here now contains 2 smaller ciphers
	public  void update(int timestamp, int hour, int stockId, Ciphertext ct) {				
		if (ct != null) {				
			TimeTuple tt = EPCloudServer.tupleTime.get(new Tuple(stockId, timestamp)); 
			if (tt.getCount()==0)
				this.statTuple.update(); 			
			tt.increaseCount();
			
			byte[] ciphertext = ct.getCipher();
			long start = System.currentTimeMillis();
			int[] lens = ct.getLens();			
			byte[] c0 = new byte[lens[0]];
			System.arraycopy(ciphertext,0,c0,0,lens[0]);
			byte[] e0 = this.cryptoHandler.extractOriginalCipher(stockId, c0);
			byte[] t0 = this.cryptoHandler.transform_simple(c0, stockId, this.policyId);			
			if (timestamp%this.windowSize==0){
				po = new byte[windowSize][e0.length];
				pt = new byte[windowSize][t0.length];				
			}
			po[timestamp%this.windowSize] = e0; 
			pt[timestamp%this.windowSize] = t0;
			
			if (timestamp%this.windowSize == (this.windowSize-1)){
				prodO = this.cryptoHandler.multiplyCiphers(po, stockId);
				prodT = this.cryptoHandler.multiplyCiphers(pt, stockId);
				byte[] c1 = new byte[lens[1]];				
				System.arraycopy(ciphertext,lens[0],c1,0,lens[1]);
				rt = this.cryptoHandler.transform_simple(c1, stockId, this.rId); 
				ro = this.cryptoHandler.extractOriginalCipher(stockId, c1);
					
				/*int val = this.cryptoHandler.decrypt_slidingWindow_Aggregate3(
						this.policyId, this.rId, prodT, prodO, rt, ro);
				log.info("DECRYPTED = "+val);*/
				byte[][] aggOriginals = new byte[1][prodO.length];
				byte[][] aggTransforms = new byte[1][prodT.length];
				byte[][] aggPrevOriginals = new byte[1][ro.length];
				byte[][] aggPrevTransforms = new byte[1][rt.length];
				aggOriginals[0] = prodO; aggTransforms[0] = prodT;
				aggPrevOriginals[0] = ro; aggPrevTransforms[0] = rt;
				TransformedCTEventAllAgg3 cte = new TransformedCTEventAllAgg3(
						this.policyId, timestamp, hour, stockId, this.rId,
						aggOriginals, aggTransforms, aggPrevOriginals,
						aggPrevTransforms);				
				EPCloud.getEPServiceProvider().getEPRuntime().sendEvent(cte);
			}											
			
			long end = System.currentTimeMillis();
			log.debug("transformation time = " + (end - start));
		}
		else
			log.error("WHAT? NULL HERE!!");
	}
}
